package com.gmlive.common.ui.dialog;

import static com.gmlive.common.ui.dialog.IkBottomSheetDialog.MessageTitleMenuFactory.ITEM_TYPE_MESSAGE;
import static com.gmlive.common.ui.dialog.IkBottomSheetDialog.MessageTitleMenuFactory.ITEM_TYPE_NORMAL_ITEM;

import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.util.SparseArray;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.TranslateAnimation;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import com.gmlive.common.ui.R;
import com.gmlive.common.ui.util.DisplayHelper;
import java.util.ArrayList;
import java.util.List;

/**
 * 底部弹出的对话框
 *
 * @作者: 姜志敏
 * @日期: 2019-08-01
 */
public class IkBottomSheetDialog extends BaseDialog {

    // 动画时长
    private final static int mAnimationDuration = 200;
    // 持有 ContentView，为了做动画
    private View mContentView;
    private boolean mIsAnimating = false;

    private OnBottomSheetShowListener mOnBottomSheetShowListener;


    public IkBottomSheetDialog(Context context) {
        super(context, R.style.IkBottomSheetDialog);
    }

    public IkBottomSheetDialog(Context context, int themeResId) {
        super(context, themeResId);
    }

    public void setOnBottomSheetShowListener(OnBottomSheetShowListener onBottomSheetShowListener) {
        mOnBottomSheetShowListener = onBottomSheetShowListener;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //noinspection ConstantConditions
        getWindow().getDecorView().setPadding(0, 0, 0, 0);

        // 在底部，宽度撑满
        WindowManager.LayoutParams params = getWindow().getAttributes();
        params.height = ViewGroup.LayoutParams.WRAP_CONTENT;
        params.gravity = Gravity.BOTTOM | Gravity.CENTER;

        int screenWidth = DisplayHelper.getScreenWidth(getContext());
        int screenHeight = DisplayHelper.getScreenHeight(getContext());
        params.width = Math.min(screenWidth, screenHeight);
        getWindow().setAttributes(params);
        setCanceledOnTouchOutside(true);
    }

    @Override
    public void setContentView(int layoutResID) {
        mContentView = LayoutInflater.from(getContext()).inflate(layoutResID, null);
        super.setContentView(mContentView);
    }

    @Override
    public void setContentView(@NonNull View view, ViewGroup.LayoutParams params) {
        mContentView = view;
        super.setContentView(view, params);
    }

    public View getContentView() {
        return mContentView;
    }

    @Override
    public void setContentView(@NonNull View view) {
        mContentView = view;
        super.setContentView(view);
    }

    /**
     * BottomSheet升起动画
     */
    private void animateUp() {
        if (mContentView == null) {
            return;
        }
	    mContentView.clearAnimation();
        TranslateAnimation translate = new TranslateAnimation(
                Animation.RELATIVE_TO_SELF, 0f, Animation.RELATIVE_TO_SELF, 0f,
                Animation.RELATIVE_TO_SELF, 1f, Animation.RELATIVE_TO_SELF, 0f
        );
        AlphaAnimation alpha = new AlphaAnimation(0, 1);
        AnimationSet set = new AnimationSet(true);
        set.addAnimation(translate);
        set.addAnimation(alpha);
        set.setInterpolator(new AccelerateInterpolator());
        set.setDuration(mAnimationDuration);
        set.setFillAfter(true);
        mContentView.startAnimation(set);
    }

    /**
     * BottomSheet降下动画
     */
    private void animateDown() {
        if (mContentView == null) {
            return;
        }
	    mContentView.clearAnimation();
        final Runnable dismissTask = () -> {
            // java.lang.IllegalArgumentException: View=com.android.internal.policy.PhoneWindow$DecorView{22dbf5b V.E...... R......D 0,0-1080,1083} not attached to window manager
            // 在dismiss的时候可能已经detach了，简单try-catch一下
            try {
                IkBottomSheetDialog.super.dismiss();
            } catch (Exception e) {
                Log.w("IkBottomSheetDialog", "dismiss error\n" + Log.getStackTraceString(e));
            }
        };
        if (mContentView.getHeight() == 0) {
            // TranslateAnimation will not call onAnimationEnd if its height is 0.
            // At this case, we run dismiss task immediately.
            dismissTask.run();
            return;
        }
        TranslateAnimation translate = new TranslateAnimation(
                Animation.RELATIVE_TO_SELF, 0f, Animation.RELATIVE_TO_SELF, 0f,
                Animation.RELATIVE_TO_SELF, 0f, Animation.RELATIVE_TO_SELF, 1f
        );
        AlphaAnimation alpha = new AlphaAnimation(1, 0);
        AnimationSet set = new AnimationSet(true);
        set.addAnimation(translate);
        set.addAnimation(alpha);
        set.setInterpolator(new DecelerateInterpolator());
        set.setDuration(mAnimationDuration);
        set.setFillAfter(true);
        set.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
                mIsAnimating = true;
            }

            @Override
            public void onAnimationEnd(Animation animation) {
                mIsAnimating = false;
                /**
                 * Bugfix： Attempting to destroy the window while drawing!
                 */
                mContentView.post(dismissTask);
            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        });
        mContentView.startAnimation(set);
    }

	@Override
    public void onStart() {
		super.onStart();
		Activity act = getOwnerActivity();
		if (act == null || act.isFinishing() || act.isDestroyed()) return;
		animateUp();
    }

    @Override
    public void show() {
        super.show();
        if (mOnBottomSheetShowListener != null) {
            mOnBottomSheetShowListener.onShow();
        }
    }

    @Override
    public void dismiss() {
        if (mIsAnimating) {
            return;
        }
        animateDown();
    }

    public interface OnBottomSheetShowListener {
        void onShow();
    }

    public static class Builder {
        private Context mContext;
        private IkBottomSheetDialog mDialog;
        private ViewFactory mViewFactory;
        private OnBottomSheetShowListener mOnBottomSheetShowListener;

        public Builder(Context context) {
            mContext = context;
        }

        public Builder setViewFactory(ViewFactory factory) {
            mViewFactory = factory;
            return this;
        }

        public Builder setOnShowListener(OnBottomSheetShowListener listener) {
            mOnBottomSheetShowListener = listener;
            return this;
        }

        public IkBottomSheetDialog build() {
            mDialog = new IkBottomSheetDialog(mContext);
            ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.WRAP_CONTENT);
            mDialog.setContentView(mViewFactory.getView(), lp);
            mDialog.setOnBottomSheetShowListener(mOnBottomSheetShowListener);

            return mDialog;
        }

        public IkBottomSheetDialog show() {
            build();
            mDialog.show();
            return mDialog;
        }
    }

    public interface ViewFactory {
        View getView();
    }

    public static class MenuBuilder {
        private Context context;
        private List<ItemBean> mMenuTextParam;
        private OnItemClickListener mItemClickListener;

        private CharSequence mNegativeText;
        private OnClickListener mNegativeListener;
        private int mNegativeTextColor;

        public MenuBuilder(Context context) {
            this.context = context;
        }

        public MenuBuilder setItems(List<String> strings, OnItemClickListener l) {
            List<ItemBean> param = new ArrayList<>();
            for (String text : strings) {
                param.add(new ItemBean(text));
            }
            mMenuTextParam = param;
            this.mItemClickListener = l;
            return this;
        }

        public MenuBuilder setItemsWithParam(List<ItemBean> param, OnItemClickListener l) {
            this.mMenuTextParam = new ArrayList<>(param);
            this.mItemClickListener = l;
            return this;
        }

        public MenuBuilder setNegativeButton(CharSequence text, OnClickListener l) {
            setNegativeButton(text, 0, l);
            return this;
        }

        public MenuBuilder setNegativeButton(CharSequence text, @ColorInt int color, OnClickListener l) {
            mNegativeText = text;
            mNegativeListener = l;
            mNegativeTextColor = color;
            return this;
        }

        public IkBottomSheetDialog build() {
            final IkBottomSheetDialog dialog = new IkBottomSheetDialog(context);

            AdapterView.OnItemClickListener listViewItemListener = new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                    mItemClickListener.onItemClick(dialog, i);
                }
            };

            MenuFactory factory = new MenuFactory(context);

            factory.setItems(mMenuTextParam);
            factory.setOnItemClickListener(listViewItemListener);
            factory.setButton(mNegativeText, mNegativeTextColor, view -> {
                if (mNegativeListener != null) {
                    mNegativeListener.onClick(dialog, -1);
                }
                dialog.dismiss();
            });

            ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.WRAP_CONTENT);
            dialog.setContentView(factory.getView(), lp);

            return dialog;
        }

        public IkBottomSheetDialog show() {
            IkBottomSheetDialog dialog = build();
            dialog.show();
            return dialog;
        }
    }

    private static class MenuFactory implements ViewFactory {
        private View mView;
        private ListView mListView;
        private Button mButton;

        public MenuFactory(Context context) {
            mView = LayoutInflater.from(context).inflate(R.layout.ik_bottom_menu_dialog, null);
            mListView = mView.findViewById(R.id.listview);
            mButton = mView.findViewById(R.id.negative_button);
        }

        public void setItems(List<ItemBean> param) {
            MenuAdapter adapter = new MenuAdapter(param);
            mListView.setAdapter(adapter);
        }

        public void setOnItemClickListener(AdapterView.OnItemClickListener listener) {
            mListView.setOnItemClickListener(listener);
        }

        public void setButton(CharSequence text, @ColorInt int textColor, View.OnClickListener listener) {
            mButton.setText(text);
            if (textColor != 0)
                mButton.setTextColor(textColor);
            mButton.setOnClickListener(listener);
        }

        @Override
        public View getView() {
            return mView;
        }
    }

    public static class ItemBean {

        public ItemBean(String text) {
            this.text = text;
        }

        public ItemBean(String text, int textColor) {
            this.text = text;
            this.textColor = textColor;
        }

        @ColorInt
        public int textColor;

        public String text;
    }

    public static class MenuTitleBuilder {
        private Context context;
        private List<CharSequence> mMenuText;
        private List<CharSequence> mMessageList;
        private OnItemClickListener mItemClickListener;

        private CharSequence mNegativeText;
        private OnClickListener mNegativeListener;
        private int mNegativeTextColor;

        public MenuTitleBuilder(Context context) {
            this.context = context;
        }

        public MenuTitleBuilder setMessage(CharSequence message) {
            mMessageList = new ArrayList<>();
            mMessageList.add(message);
            return MenuTitleBuilder.this;
        }

        public MenuTitleBuilder setItems(List<CharSequence> strings, OnItemClickListener l) {
            this.mMenuText = new ArrayList<>(strings);
            this.mItemClickListener = l;
            return this;
        }

        public MenuTitleBuilder setNegativeButton(CharSequence text, OnClickListener l) {
            setNegativeButton(text, 0, l);
            return this;
        }

        public MenuTitleBuilder setNegativeButton(CharSequence text, @ColorInt int color, OnClickListener l) {
            mNegativeText = text;
            mNegativeListener = l;
            mNegativeTextColor = color;
            return this;
        }

        public IkBottomSheetDialog build() {
            final IkBottomSheetDialog dialog = new IkBottomSheetDialog(context);

            MessageTitleMenuFactory.OnItemClick listViewItemListener = (int position) -> {
                if (null != mItemClickListener)
                    mItemClickListener.onItemClick(dialog, position);
            };

            MessageTitleMenuFactory factory = new MessageTitleMenuFactory(context, (ViewGroup) dialog.getContentView());
            SparseArray<List<CharSequence>> list = new SparseArray<>();
            list.put(ITEM_TYPE_MESSAGE, mMessageList);
            list.put(ITEM_TYPE_NORMAL_ITEM, mMenuText);
            factory.setView(list);
            factory.setItemClickLis(listViewItemListener);
            factory.setButton(mNegativeText, mNegativeTextColor, (View view) -> {
                if (mNegativeListener != null) {
                    mNegativeListener.onClick(dialog, -1);
                }
                dialog.dismiss();
            });

            ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.WRAP_CONTENT);
            dialog.setContentView(factory.getView(), lp);

            return dialog;
        }

        public IkBottomSheetDialog show() {
            IkBottomSheetDialog dialog = build();
            dialog.show();
            return dialog;
        }
    }

    public static class MessageTitleMenuFactory implements ViewFactory {

        public final static int ITEM_TYPE_MESSAGE = 1;

        public final static int ITEM_TYPE_NORMAL_ITEM = 2;

        private View mView;

        private LinearLayout mListLayout;

        private Button mButton;

        private List<CharSequence> mMessageList;

        private List<CharSequence> mItemList;

        private List<View> mViewList;

        private OnItemClick mItemClick;

        public MessageTitleMenuFactory(Context context, ViewGroup rootView) {
            mView = LayoutInflater.from(context).inflate(R.layout.ik_bottom_message_menu_dialog, rootView, false);
            mListLayout = mView.findViewById(R.id.list_layout);
            mButton = mView.findViewById(R.id.negative_button);
        }

        @Override
        public View getView() {
            return mView;
        }

        public void setView(SparseArray<List<CharSequence>> viewList) {
            mMessageList = viewList.get(ITEM_TYPE_MESSAGE);
            mItemList = viewList.get(ITEM_TYPE_NORMAL_ITEM);
            addAllView();
        }

        public void setItemClickLis(OnItemClick lis) {
            mItemClick = lis;
        }

        public void setButton(CharSequence text, @ColorInt int textColor, View.OnClickListener listener) {
            mButton.setText(text);
            if (textColor != 0)
                mButton.setTextColor(textColor);
            mButton.setOnClickListener(listener);
        }

        private void addAllView() {
            if (mListLayout.getChildCount() > 0)
                mListLayout.removeAllViews();
            mViewList = new ArrayList<>();
            int count = getCount();
            if (0 == count)
                return;
            if (null != mMessageList && !mMessageList.isEmpty()) {
                for (CharSequence item : mMessageList) {
                    TextView view = (TextView) LayoutInflater.from(mListLayout.getContext())
                            .inflate(R.layout.ik_bottom_menu_list_message_item,
                                    mListLayout,
                                    false);
                    view.setText(item);
                    mViewList.add(view);
                }
            }
            if (null != mItemList && !mItemList.isEmpty()) {
                final int itemListSize = mItemList.size();
                for (int i = 0; i < itemListSize; i++) {
                    CharSequence item = mItemList.get(i);
                    TextView view = (TextView) LayoutInflater.from(mListLayout.getContext())
                            .inflate(R.layout.ik_bottom_menu_list_item,
                                    mListLayout,
                                    false);
                    view.setText(item);
                    final int position = i;
                    view.setOnClickListener((View v) -> {
                        if (null != mItemClick)
                            mItemClick.onClick(position);
                    });
                    mViewList.add(view);
                }
            }
            if (mViewList.size() == 1) {
                View view = mViewList.get(0);
                view.setBackgroundResource(R.drawable.ik_bottom_menu_list_item_press_single);
                mListLayout.addView(view);
                return;
            }
            final int listSize = mViewList.size();
            for (int i = 0; i < listSize; i++) {
                View view = mViewList.get(i);
                if (i == 0) {
                    view.setBackgroundResource(R.drawable.ik_bottom_menu_list_item_press_top);
                    mListLayout.addView(view);
                    View divide = LayoutInflater.from(mListLayout.getContext())
                            .inflate(R.layout.ik_bottom_menu_list_divide,
                                    mListLayout,
                                    false);
                    mListLayout.addView(divide);
                    continue;
                }
                if (i == listSize - 1) {
                    view.setBackgroundResource(R.drawable.ik_bottom_menu_list_item_press_bottom);
                    mListLayout.addView(view);
                    continue;
                }
                view.setBackgroundResource(R.drawable.ik_bottom_menu_list_item_press_middle);
                mListLayout.addView(view);
                View divide = LayoutInflater.from(mListLayout.getContext())
                        .inflate(R.layout.ik_bottom_menu_list_divide,
                                mListLayout,
                                false);
                mListLayout.addView(divide);
            }
        }

        private int getCount() {
            int count = 0;
            if (null != mMessageList)
                count += mMessageList.size();
            if (null != mItemList)
                count += mItemList.size();
            return count;
        }

        @FunctionalInterface
        interface OnItemClick {
            void onClick(int position);
        }
    }

    public interface OnItemClickListener {
        void onItemClick(DialogInterface dialog, int which);
    }


    private static class MenuAdapter extends BaseAdapter {
        private static final int TYPE_TOP = 0;
        private static final int TYPE_MIDDLE = 1;
        private static final int TYPE_BOTTOM = 2;
        private static final int TYPE_SINGLE = 3;

        private List<ItemBean> mItems;

        public MenuAdapter(List<ItemBean> list) {
            mItems = new ArrayList<>(list);
        }

        @Override
        public int getCount() {
            return mItems != null ? mItems.size() : 0;
        }

        @Override
        public Object getItem(int i) {
            return null;
        }

        @Override
        public long getItemId(int i) {
            return i;
        }

        @Override
        public int getItemViewType(int position) {
            if (getCount() == 1) {
                return TYPE_SINGLE;
            }

            if (position == 0) {
                return TYPE_TOP;
            } else if (position == getCount() - 1) {
                return TYPE_BOTTOM;
            } else {
                return TYPE_MIDDLE;
            }
        }

        @Override
        public View getView(int position, View view, ViewGroup viewGroup) {
            TextView titleView;
            if (view == null) {
                titleView = (TextView) LayoutInflater.from(viewGroup.getContext())
                        .inflate(R.layout.ik_bottom_menu_list_item, viewGroup, false);
            } else {
                titleView = (TextView) view;
            }

            applyStyle(titleView, getItemViewType(position));

            String text = mItems.get(position).text;
            if (null == text)
                text = "";

            titleView.setText(text);

            int textColor = mItems.get(position).textColor;
            if (textColor != 0)
                titleView.setTextColor(textColor);
            else
                titleView.setTextColor(Color.parseColor("#0076FF"));

            return titleView;
        }

        private void applyStyle(View view, int type) {
            switch (type) {
                case TYPE_TOP:
                    view.setBackgroundResource(R.drawable.ik_bottom_menu_list_item_top);
                    break;
                case TYPE_MIDDLE:
                    view.setBackgroundResource(R.drawable.ik_bottom_menu_list_item_middle);
                    break;
                case TYPE_BOTTOM:
                    view.setBackgroundResource(R.drawable.ik_bottom_menu_list_item_bottom);
                    break;
                case TYPE_SINGLE:
                    view.setBackgroundResource(R.drawable.ik_bottom_menu_list_item_single);
                    break;
            }
        }
    }
}
